#include <sys/socket.h>
#include "common_impl.h"
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>

/* variables globales */
#define BACKLOG 1024
#define MAXBUF 1024
#define PORT 33000

/* un tableau gerant les infos d'identification */
/* des processus dsm */
dsm_proc_t *proc_array = NULL;

/* le nombre de processus effectivement crees */
volatile int num_procs_creat = 0;

void usage(void) {
	fprintf(stdout, "Usage : dsmexec machine_file executable arg1 arg2 ...\n");
	fflush(stdout);
	exit(EXIT_FAILURE);
}

void sigchld_handler(int sig) {
	/* on traite les fils qui se terminent */
	/* pour eviter les zombies */
}

int readline(int fd, void *str, int max_len);
int sendline(int fd, const void *str, size_t maxlen);
void clean(char *buffer);

void toto(void) {
	return ;
}

int main(int argc, char **argv) {
	if (argc < 3)
		usage();
	else {
		pid_t pid;
		int num_procs = 0;
		int i = 0;
		int max;
		int sock_serv;
		char *file_name = argv[1];
		char line[100];
		struct sockaddr_in servaddr;
		FILE *f;
		char *ret;
		char **machine_name;
		char **newargv;
		int status = 0;;
		int sock_dsm;
		char* buffer = NULL;
		fd_set readfds;
		char *machine_dsm;
		pid_t pid_dsm;
		char *salut = "salut2";

		/* Mise en place d'un traitant pour recuperer les fils zombies*/
		/* XXX.sa_handler = sigchld_handler; */

		/* lecture du fichier de machines */
		/* 1- on recupere le nombre de processus a lancer */
		/* 2- on recupere les noms des machines : le nom de */
		/* la machine est un des elements d'identification */

		f = fopen(file_name, "r");

		ret = fgets(line, 100, f);
		while (ret != NULL) {
			num_procs++;
			ret = fgets(line, 100, f);
		}
		fclose(f);

		printf("nbre processus : %d\n", num_procs);

		proc_array = malloc(sizeof(dsm_proc_t) * num_procs);
		machine_name = malloc(sizeof(char*) * num_procs);

		f = fopen(file_name, "r");

		for (i=0;i<num_procs;i++) {
			fgets(line, 100, f);
			machine_name[i] = malloc(100*sizeof(char));
			strcpy(machine_name[i], line);

			proc_array[i].connect_info.rank = i;
			proc_array[i].machine_name = machine_name[i];
		}
		fclose(f);

		/* creation de la socket d'ecoute */
		if ((sock_serv = socket(AF_INET, SOCK_STREAM, 0)) == -1)
			ERROR_EXIT("socket");

		memset(&servaddr, 0, sizeof(servaddr));
		servaddr.sin_family = AF_INET;
		servaddr.sin_port = htons(PORT);
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

		max = sock_serv;

		/*while (1) {

				FD_ZERO(&readfds);

				//FD_SET(list_s, &readfds);


		}*/


		if (bind(sock_serv, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
			close(sock_serv);
			ERROR_EXIT("bind");
		}

		/* + ecoute effective */
		if (listen(sock_serv, BACKLOG) == -1)
			ERROR_EXIT("listen");

		/* creation des fils */
		for (i = 1; i <= num_procs; i++) {

			/* creation du tube pour rediriger stdout */

			if (pipe(proc_array[i].std_out) == -1)
				ERROR_EXIT("pipe");

			/* creation du tube pour rediriger stderr */

			if (pipe(proc_array[i].std_err) == -1)
				ERROR_EXIT("pipe");

			pid = fork();

			if (pid == -1) {
				ERROR_EXIT("fork");
			}
			else if (pid == 0) { /* fils */

				/* redirection stdout */

				close(proc_array[i].std_out[0]);
				dup2(proc_array[i].std_out[1], STDOUT_FILENO);
				close(proc_array[i].std_out[1]);

				/* redirection stderr */

				/*close(proc_array[i].std_err[0]);
				dup2(proc_array[i].std_err[1], STDERR_FILENO);
				close(proc_array[i].std_err[1]);*/

				write(STDOUT_FILENO, salut, strlen(salut));

				/* Creation du tableau d'arguments pour le ssh */

				newargv = malloc(sizeof(char*) * (argc - 2));

				newargv[0] = malloc(100*sizeof(char));
				strcpy(newargv[0], "ssh");

				newargv[1] = malloc(100*sizeof(char));
				strcpy(newargv[1], "dsmwrap");

				newargv[2] = malloc(100*sizeof(char));
				strcpy(newargv[2], proc_array[i].machine_name);

				for (i=3;i <= argc - 3; i++) {
					newargv[i] = malloc(100*sizeof(char));
					strcpy(newargv[i], argv[i + 2]);
				}

				newargv[argc - 2] = malloc(100*sizeof(char));
				strcpy(newargv[argc - 2], "NULL");

				/* jump to new prog : */
				 execvp("ssh", newargv);

			} else if (pid > 0) { /* pere */
				/* fermeture des extremites des tubes non utiles */

				sleep(2);

				close(proc_array[i].std_out[1]);
				dup2(proc_array[i].std_out[0], STDIN_FILENO);
				close(proc_array[i].std_out[0]);

				/*while(1) {
					FD_ZERO(&readfds);

					FD_SET(STDIN_FILENO, &readfds);

					if (select(STDIN_FILENO + 1, &readfds, NULL, NULL, NULL) == -1)
						ERROR_EXIT("select");
*/
						read(STDIN_FILENO, buffer, MAXBUF - 1);
						fprintf(stdout, "%s\n", buffer);

			/*	}


*/
				num_procs_creat++;
			}
		}

		for (i = 0; i < num_procs; i++) {

			/* on accepte les connexions des processus dsm */

			//if ((sock_dsm = accept(sock_serv, NULL, NULL)) < 0)
			//	ERROR_EXIT("accept");

			/*  On recupere le nom de la machine distante */
			/* 1- d'abord la taille de la chaine */
			/* 2- puis la chaine elle-meme */

			//readline(sock_dsm, buffer, MAXBUF - 1);

			/* On recupere le pid du processus distant  */

			//read(sock_dsm, pid_dsm, 5*sizeof(pid_t));

			/* On recupere le numero de port de la socket */
			/* d'ecoute des processus distants */
		}

		/* envoi du nombre de processus aux processus dsm*/

		/* envoi des rangs aux processus dsm */

		/* envoi des infos de connexion aux processus */

		/* gestion des E/S : on recupere les caracteres */
		/* sur les tubes de redirection de stdout/stderr */
		/* while(1)
		 {
		 je recupere les infos sur les tubes de redirection
		 jusqu'à ce qu'ils soient inactifs (ie fermes par les
		 processus dsm ecrivains de l'autre cote ...)

		 };
		 */

		/* on attend les processus fils */

		for (i = 1; i <=num_procs; i++) {
		wait(&status);
		}

		/* on ferme les descripteurs proprement */

		/* on ferme la socket d'ecoute */

		if (close(sock_serv) < 0)
			ERROR_EXIT("close");
	}
	exit(EXIT_SUCCESS);
}

int readline(int fd, void *str, int max_len) {
	int n, rc;
	char c;
	char* buffer;

	buffer = str;
	for (n = 1; n < max_len; n++) {
		if ((rc = read(fd, &c, 1)) == 1) {
			*buffer++ = c;
			if (c == '\n')
				break;
		} else {
			if (rc == 0) {
				if (n == 1)
					return 0;
				else
					break;
			}
			if (rc == -1) {
				if (errno == EINTR)
					continue;
				else
					return -1;
			}
		}
	}
	*buffer = '\0';
	return n;
}

int sendline(int fd, const void *str, size_t maxlen) {
	int nleft; //caractères restant à écrire
	int nwritten; // caractères déjà écrits

	const char* buffer;

	buffer = str;
	nleft = maxlen;
	while (nleft > 0) {
		if ((nwritten = write(fd, buffer, nleft)) < 0) {
			if (errno == EINTR)
				nwritten = 0;
			else
				return -1;
		}
		nleft -= nwritten;
		buffer += nwritten;
	}
	return maxlen;
}

void clean(char *buffer) {
	char* p = NULL;
	p = strchr(buffer, '\n');
	if (p == NULL) {
		int c;
		while ((c = getchar()) != '\n' && c != EOF) {
		}
	}
}
